#ifndef _M_MSGQUEUE_H_
#define _M_MSGQUEUE_H_

#include <iostream>
#include <google/protobuf/map.h>
#include <string>
#include <vector>
#include <cassert>
#include <sstream>
#include <functional>
#include <mutex>

#include "../mqcommon/mqProto.pb.h"
#include "../mqcommon/logger.hpp"
#include "../mqcommon/helper.hpp"

namespace MyRabbitMQ
{
    //队列数据类
    class MsgQueue
    {
    public:
        using ptr = std::shared_ptr<MsgQueue>;
        MsgQueue(){}

        MsgQueue(const std::string& name,bool isDurable,bool isUnique,bool isAutoDelete, 
        const google::protobuf::Map<std::string, std::string>& args)
        :m_name(name),m_isDurable(isDurable),m_isUnique(isUnique),m_isAutoDelete(isAutoDelete),m_args(args)
        {}

        MsgQueue(const MsgQueue&) = delete;
        MsgQueue(MsgQueue&&) = default;

        
        // 获取额外参数
        std::string getArgs()
        {
            std::string str;
            for (auto &f : m_args)
            {
                str += f.first + "=" + f.second + "&";
            }
            return str;
        }

        // 设置额外参数值
        void setArgs(const std::string &str)
        {
            std::vector<std::string> vt;
            StringHelper::split(str, "&", &vt);

            for (auto &f : vt)
            {
                size_t pos = f.find("=");
                std::string key = f.substr(0, pos);
                std::string value = f.substr(pos + 1);
                m_args[key] = value;
            }
        }

    public:
        std::string m_name;
        bool m_isDurable;
        bool m_isUnique;
        bool m_isAutoDelete;
        google::protobuf::Map<std::string, std::string> m_args; // 其他参数
    };

    using MsgQueueMap = std::unordered_map<std::string,MsgQueue::ptr>;
    
    //队列数据持久化层面管理类
    class MsgQueueMapper
    {
    public:
        using ptr = std::shared_ptr<MsgQueueMapper>;
        MsgQueueMapper(const std::string& dbfilename)
        :m_sqlite(dbfilename)
        {
            //创建父目录
            std::string parentDir = FileHelper::parentDirectory(dbfilename);
            FileHelper::createDirectory(parentDir);

            //打开数据库文件,如果不存在则断言
            assert(m_sqlite.open());

            //创建表
            this->createTable();
        }

        //创建表
        bool createTable()
        {
            std::string sql = "create table if not exists msgQueue_table (\
            name varchar(32) primary key, unique_queue int, durable int, auto_delete int, args varchar(128));";

            bool ret = m_sqlite.exec(sql,nullptr,nullptr);
            
            //如果表都创建失败了,那就不要再继续进行下去了
            if(!ret)
            {
                LOG(logLevel::ERROR) << "创建队列数据表失败! 程序即将退出" << std::endl;
                //直接异常退出程序
                abort();
            }

            return true;
        }

        //删除表
        bool removeTable()
        {
            std::string sql = "drop table if exists msgQueue_table;";
            
            bool ret = m_sqlite.exec(sql,nullptr,nullptr);

            if(!ret)
            {
                LOG(logLevel::ERROR) << "删除队列数据表失败! 程序即将退出" << std::endl;
                //直接异常退出程序
                abort();
            }
            return true;
        }

        //新增队列
        bool insert(const MsgQueue::ptr& ptr)
        {
            std::stringstream ss;

            ss << "insert into msgQueue_table values(";
            ss << "'" << ptr->m_name << "'" << ",";
            ss << ptr->m_isUnique << ",";
            ss << ptr->m_isDurable << ",";
            ss << ptr->m_isAutoDelete << ",";
            ss << "'" << ptr->getArgs() << "'" << ");";

            return m_sqlite.exec(ss.str(),nullptr,nullptr);
        }

        //删除队列
        bool remove(const std::string& name)
        {
            std::stringstream ss;
            ss << "delete from msgQueue_table where name = '" <<  name << "';";
            return m_sqlite.exec(ss.str(),nullptr,nullptr);       
        }                                                         

        //恢复历史数据                                       
        MsgQueueMap recovery()                              
        {                                                         
            MsgQueueMap result;                                   
            std::stringstream ss;                                 
            ss << "select * from msgQueue_table;";                
            m_sqlite.exec(ss.str(),recoverCallback,&result);
            return result;                                         
        }
    
    private:
        SqliteHelper m_sqlite;

        //存入位置, 一行数据的列数, 一行数据的字符指针数组, 每列字段名称
        static int recoverCallback(void *args, int row, char ** dataOfCol, char **rowOfName)
        {
            MsgQueueMap* result = reinterpret_cast<MsgQueueMap*>(args);
            auto msgQueue_ptr = std::make_shared<MsgQueue>();

            msgQueue_ptr->m_name = dataOfCol[0];
            msgQueue_ptr->m_isUnique = static_cast<bool>(std::stoi(dataOfCol[1]));
            msgQueue_ptr->m_isDurable = static_cast<bool>(std::stoi(dataOfCol[2]));
            msgQueue_ptr->m_isAutoDelete = static_cast<bool>(std::stoi(dataOfCol[3]));
            
            //如果存在args
            if(dataOfCol[4])
            {
                msgQueue_ptr->setArgs(dataOfCol[4]);
            }
            result->insert(std::make_pair(msgQueue_ptr->m_name,msgQueue_ptr));
            return 0;
        }
    };

    //队列数据内存层面管理类
    class MsgQueueManager
    {
    public:
        using ptr = std::shared_ptr<MsgQueueManager>;
        MsgQueueManager(const std::string& dbfilename)
        :m_mapper(dbfilename)
       {
            m_msgQueues = m_mapper.recovery();
       }

        //声明队列
        bool declareMsgQueue(const std::string &name,bool isUnique, bool isDurable, bool isAutoDelete, const google::protobuf::Map<std::string, std::string> &args)
        {
            //加锁
            std::unique_lock<std::mutex>(m_mtx);
            
            //判断交换机是否存在, 存在则直接返回
            if(m_msgQueues.find(name) != m_msgQueues.end()) 
            {
                return true;
            }

            //交换机不存在, 进行添加逻辑
            auto ptr = std::make_shared<MsgQueue>(name,isUnique,isDurable,isAutoDelete,args);
           
            //如果设置持久化标志, 需要添加到数据库中, 由于该操作可能失败, 故放在内存层面添加之前
            if(isDurable)
            {
                bool ret = m_mapper.insert(ptr);                        
                if(!ret)
                {
                    LOG(logLevel::ERROR) << "执行失败:进行持久化时出现问题" << std::endl;
                    return false;
                }
            }
            //添加到内存中
            m_msgQueues.insert(std::make_pair(name,ptr));     
            return true;   
        }

        //删除队列
        bool deleteMsgQueue(const std::string& name)
        {
            //加锁
            std::unique_lock<std::mutex>(m_mtx);

            //寻找内存中的交换机
            auto it = m_msgQueues.find(name);
            
            if(it == m_msgQueues.end())
            {
                return true;
            }

            //如果设置持久化标志, 需要先解除管理
            if(it->second->m_isDurable) 
            {
                bool ret = m_mapper.remove(name);
                if(!ret)
                {
                    LOG(logLevel::ERROR) << "执行失败:进行持久化时出现问题" << std::endl;
                    return false;
                }
            }
            //解除内存管理
            m_msgQueues.erase(it);  
            return true;      
        }
        
        //获取指定队列
        MsgQueue::ptr getMsgQueue(const std::string& name)
        {
            std::unique_lock<std::mutex>(m_mtx);

            auto it = m_msgQueues.find(name);
            if(it == m_msgQueues.end())
            {
                return MsgQueue::ptr();
            }

            return it->second;            
        }

        //获取全部队列
        MsgQueueMap getMsgQueueAll()
        {
            std::unique_lock<std::mutex>(m_mtx);
            return m_msgQueues;
        }

        //判断指定队列是否存在
        bool exists(const std::string& name)
        {
            std::unique_lock<std::mutex>(m_mtx);

            auto it = m_msgQueues.find(name);
            if(it == m_msgQueues.end()) return false;
            else return true;            
        }

        //获取队列管理数量
        size_t size()
        {
            std::unique_lock<std::mutex>(m_mtx); 
            return m_msgQueues.size();
        }

        //清理所有队列
        void clear()
        {
            std::unique_lock<std::mutex>(m_mtx);
            m_mapper.removeTable(); //删表等于变相清理数据
            m_msgQueues.clear();
        }
    
    private:
        std::mutex m_mtx;
        MsgQueueMapper m_mapper;
        MsgQueueMap m_msgQueues;
    };

    
};

#endif